#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/time.h>
#include <pthread.h>

#define NUM_THREADS	10

/*estrutura usada para o número aleatório*/
struct BoxMullerState{
	double x1, x2, w, y1, y2;
     int useLast;
     struct drand48_data random;
};

/*estrutura usada na thread*/
typedef struct {
	double s, e, r, ro, tempo, t, media, desvio, trials;
	int n;
}PARAMETROS;

/* Inicializando a estrutura*/
void initBoxMullerState(struct BoxMullerState* state){
     state->random.__init = 0;
     state->useLast = 0;
        
     struct timeval now;
	gettimeofday(&now, NULL);
	state->random.__x[0] = now.tv_usec;
}

/*Calculando o número aleatório de distribuição normal, com média 0 e variância de 1*/
double boxMullerRandom(struct BoxMullerState* state){
	if (state->useLast){
		state->y1 = state->y2;
          state->useLast = 0;
     }
	else{
		do{
			drand48_r(&state->random, &state->x1);
			state->x1 = 2.0 * state->x1 - 1.0;
			drand48_r(&state->random, &state->x2);
			state->x2 = 2.0 * state->x2 - 1.0;
			state->w = state->x1 * state->x1 + state->x2 * state->x2;
		}while (state->w >= 1.0);
		state->w = sqrt((-2.0 * log(state->w)) / state->w);
		state->y1 = state->x1 * state->w;
		state->y2 = state->x2 * state->w;
		state->useLast = 1;
	}
	return state->y1;
}

/*código de cada thread*/
void *thread_code(void *parametro){
	PARAMETROS *param =(PARAMETROS *)parametro;
	double *trials;
	struct BoxMullerState state;
	int i, m;
	m = (param->n/NUM_THREADS);
	
	initBoxMullerState(&state);
	/*Alocação do vetor que irá armazenar os valores obtidos pelo blackscholes*/ 
	trials = (double *)malloc (sizeof(double)*(m));

	/*calculo do blackscholes*/
	for(i =0; i<m; i++){
		param->t = param->s * exp((param->r-(param->ro*param->ro)/2)*param->tempo+param->ro*sqrt(param->tempo)*boxMullerRandom(&state));
		trials[i] = exp(-param->r*param->tempo)*fmax(param->t-param->e, 0.0);
		param->media += trials[i];
		param->trials = trials[i];
	}
	/*calculo da média na thread*/
	param->media = param->media/m;

	/*calculo do desvio padrão na thread*/
	for(i =0; i< m; i++){
		param->desvio += pow(trials[i]-param->media, 2);
	}
	pthread_exit((void*)NULL);
}


int main (void){
	double media, desvio, intervalo, maximo, minimo;
	int i;
	void *status;
	
	PARAMETROS *param;
	param = (PARAMETROS *)malloc (sizeof(PARAMETROS)*(NUM_THREADS));

	/*criando as threads*/
	pthread_t threads[NUM_THREADS];

	/*Leitura dos paramêtros*/
	scanf("%lf %lf %lf %lf %lf %d",&param[0].s, &param[0].e, &param[0].r, &param[0].ro, &param[0].tempo, &param[0].n);

	/*inicializando as variáveis*/
	media=0.0;
	desvio = 0.0;
	intervalo = 0.0;
	maximo= 0.0;
	minimo= 0.0;
	for(i=1; i<NUM_THREADS; i++){
		param[i].s = param[0].s;
		param[i].e = param[0].e;
		param[i].r = param[0].r;
		param[i].ro = param[0].ro;
		param[i].tempo = param[0].tempo;
		param[i].n = param[0].n;
	}

	/*criando as threads*/
	for (i=0; i<NUM_THREADS; i++){
		pthread_create(&threads[i], NULL, thread_code, &param[i]);
	}
	
	/*sincronizando a parada das threads*/
	for (i=0; i<NUM_THREADS; i++){
		//printf("chegou %d %lf\n",i,  param[i].media);
		pthread_join(threads[i], &status);
	}
	/*calculando média e desvio padrão de todas as threads*/
	for (i=0; i<NUM_THREADS; i++){
		media = media + param[i].media;		
		desvio = desvio + pow(param[i].trials-param[i].media, 2);
	}
	media = media/NUM_THREADS;
	desvio = sqrt(desvio/NUM_THREADS);

	/*calculo do intervalo de confiança*/
	intervalo = 1.96*(desvio/sqrt(param[0].n));

	/*calculo do mínimo e máximo*/
	minimo = media - intervalo;
	maximo = media + intervalo;
	

	/*impressão*/
	printf("S \t%.0lf\n", param[0].s);
	printf("E \t%.0lf\n", param[0].e);
	printf("r \t%.0lf\n", param[0].r);
	printf("sigma \t%.0lf\n", param[0].ro); 
	printf("T \t%.0lf\n", param[0].tempo);
	printf("M \t%d\n", param[0].n);
	printf("Confidence interval: (%.4lf, %.4lf)\n",minimo, maximo);
	free(param);
	return 1;
}
